home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / adduser / RCS / adduser.c,v < prev    next >
Encoding:
Text File  |  1991-12-16  |  44.8 KB  |  2,024 lines

  1. head     1.13;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.13
  10. date     91.12.16.12.12.40;  author kupfer;  state Exp;
  11. branches ;
  12. next     1.12;
  13.  
  14. 1.12
  15. date     91.12.12.17.41.28;  author shirriff;  state Exp;
  16. branches ;
  17. next     1.11;
  18.  
  19. 1.11
  20. date     91.10.10.10.06.58;  author jhh;  state Exp;
  21. branches ;
  22. next     1.10;
  23.  
  24. 1.10
  25. date     91.06.10.12.07.34;  author kupfer;  state Exp;
  26. branches ;
  27. next     1.9;
  28.  
  29. 1.9
  30. date     91.06.04.16.52.43;  author kupfer;  state Exp;
  31. branches ;
  32. next     1.8;
  33.  
  34. 1.8
  35. date     91.06.03.17.16.19;  author kupfer;  state Exp;
  36. branches ;
  37. next     1.7;
  38.  
  39. 1.7
  40. date     91.05.29.13.39.45;  author kupfer;  state Exp;
  41. branches ;
  42. next     1.6;
  43.  
  44. 1.6
  45. date     90.12.19.16.42.32;  author kupfer;  state Exp;
  46. branches ;
  47. next     1.5;
  48.  
  49. 1.5
  50. date     90.12.19.16.31.06;  author rab;  state Exp;
  51. branches ;
  52. next     1.4;
  53.  
  54. 1.4
  55. date     90.08.13.21.03.03;  author rab;  state Exp;
  56. branches ;
  57. next     1.3;
  58.  
  59. 1.3
  60. date     90.08.13.21.01.17;  author shirriff;  state Exp;
  61. branches ;
  62. next     1.2;
  63.  
  64. 1.2
  65. date     90.06.28.15.15.20;  author rab;  state Exp;
  66. branches ;
  67. next     1.1;
  68.  
  69. 1.1
  70. date     90.03.21.11.05.27;  author rab;  state Exp;
  71. branches ;
  72. next     ;
  73.  
  74.  
  75. desc
  76. @@
  77.  
  78.  
  79. 1.13
  80. log
  81. @Be less generous with permissions to files.
  82. @
  83. text
  84. @/* 
  85.  * adduser.c --
  86.  *
  87.  *    Add a user to /etc/passwd, create a home directory,
  88.  *      create a .project file, add them to the sprite-users
  89.  *      mailing list, and send them mail to inform them that
  90.  *      their account is ready.
  91.  *
  92.  * Copyright 1990 Regents of the University of California
  93.  * Permission to use, copy, modify, and distribute this
  94.  * software and its documentation for any purpose and without
  95.  * fee is hereby granted, provided that the above copyright
  96.  * notice appear in all copies.  The University of California
  97.  * makes no representations about the suitability of this
  98.  * software for any purpose.  It is provided "as is" without
  99.  * express or implied warranty.
  100.  */
  101.  
  102. #ifndef lint
  103. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.12 91/12/12 17:41:28 shirriff Exp Locker: kupfer $";
  104. #endif /* not lint */
  105.  
  106. #include "common.h"
  107. #include <sprite.h>
  108. #include <assert.h>
  109. #include <bstring.h>
  110. #include <ctype.h>
  111. #include <errno.h>
  112. #include <fcntl.h>
  113. #include <grp.h>
  114. #include <signal.h>
  115. #include <stdio.h>
  116. #include <stdlib.h>
  117. #include <string.h>
  118. #include <sys/file.h>
  119. #include <sys/ioctl.h>
  120. #include <sys/param.h>
  121. #include <sys/stat.h>
  122. #include <sys/wait.h>
  123. #include <unistd.h>
  124.  
  125. /* This is where we keep a prototype home directory. */
  126. #define NEWUSER_DIR    "/user1/newuser"
  127.  
  128. /* This is the host that has the master UID database. */
  129. #define DATABASE_HOST    "thalm"
  130.  
  131. #if 0
  132. /* XXX MAIL_TMP doesn't allow for concurrent addusers */
  133. #define MAIL_TMP    "/tmp/mail.adduser"
  134.  
  135. #define MAIL_MSG    mail_message
  136.  
  137. static CONST char mail_message[] = "\
  138. Your Sprite account is ready.\n\
  139. If you have any problems or questions\n\
  140. let me know.\n\n\
  141. Your passwd is < enter passwd >\n";
  142. #endif /* 0 */
  143.  
  144. static char whoami[0x100];
  145.  
  146. /* Forward references: */
  147. static void add2MailingList _ARGS_((CONST char *list, CONST char *name));
  148. static void cleanup _ARGS_((int sig));
  149. static int  copy _ARGS_((CONST char *from, CONST char *to, int mode));
  150. static void createHomeDirectory _ARGS_((CONST char *dir, CONST char *username,
  151.            CONST char *project, CONST char *forward, int uid, int gid));
  152. static char *getHomeDir _ARGS_((void));
  153. static char *getPasswdEntryFromDataBase _ARGS_((void));
  154. static char *getPasswdEntryInteractive _ARGS_((CONST struct passwd *pwd));
  155. static char *getPasswdEntryFromUser _ARGS_((void));
  156. static void insertPasswdEntry _ARGS_((CONST struct passwd *newpw));
  157. static void makeLinktoHomeDir _ARGS_((CONST char *homedir,
  158.                       CONST char *username));
  159. static int  parsePasswdEntry _ARGS_((char *p, struct passwd *ps));
  160. static void printPasswdEntry _ARGS_((CONST struct passwd *pwd,
  161.                      CONST char *dir));
  162. static int  sed _ARGS_((CONST char *filename, CONST char *expr, int mode));
  163. static char *xmalloc _ARGS_((int n));
  164.  
  165. /*
  166.  * Flags to keep track of what the program has done, so we can back out
  167.  * semi-gracefully if the program is interrupted.
  168.  */
  169. enum Step { NOT_DONE_YET, DONE, SKIP_THIS_STEP };
  170. static enum Step create_ptmp_file      = NOT_DONE_YET;
  171. static enum Step move_ptmp_to_passwd   = NOT_DONE_YET;
  172. static enum Step create_home_dir       = NOT_DONE_YET;
  173. static enum Step edit_mailaliases_file = NOT_DONE_YET;
  174. static enum Step make_symlink          = NOT_DONE_YET;
  175. static char real_homedir[MAXPATHLEN];
  176. static char sym_homedir[MAXPATHLEN];
  177. static char project[BUFFER_SIZE];
  178. static char forward[BUFFER_SIZE];
  179.  
  180.  
  181. /*
  182.  *----------------------------------------------------------------------
  183.  *
  184.  * main --
  185.  *
  186.  *    Get account information from the user, or from the ucb database.
  187.  *      Use the information to create an account.
  188.  *
  189.  * Results:
  190.  *    0 exit status if no errors.  Non-zero if there were
  191.  *      problems.
  192.  *
  193.  * Side effects:
  194.  *    Account is created.  If the program is interrupted, it is
  195.  *      supposed to be able to back out with out changing anything.
  196.  *
  197.  *----------------------------------------------------------------------
  198.  */
  199.  
  200. void
  201. main(argc, argv)
  202.     int argc;
  203.     char **argv;
  204. {
  205.     struct passwd passwdStruct;
  206.     int c;
  207.     char *entry;
  208.     char *dir;
  209.     char *username;
  210.     struct passwd *pwd;
  211.     char from[MAXPATHLEN], to[MAXPATHLEN], *tend, *fend;
  212.     int fd;
  213.  
  214.     if ((pwd = getpwuid(getuid())) == NULL) {
  215.     fprintf(stderr, "getpwuid failed: %s\n", strerror(errno));
  216.     exit(EXIT_FAILURE);
  217.     }
  218.     strcpy(whoami, pwd->pw_name);
  219. #ifndef TEST
  220.     /* 
  221.      * Do any necessary security checks and setup.
  222.      */
  223.     SecurityCheck();
  224. #endif
  225.     signal(SIGINT, cleanup);
  226.     printf(
  227.      "Enter 1 if you already have a /etc/passwd file from another machine.\n");
  228.     printf("Enter 2 if you want to fetch an entry from the ucb data base.\n");
  229.     printf("Enter 3 if you want to enter the information interactively.\n");
  230.     printf("Enter q to quit\n");
  231.     for (;;) {
  232.     printf("Please choose 1, 2 or 3: ");
  233.     c = raw_getchar();
  234.     printf("\n");
  235.     switch(c) {
  236.     case '1':  entry = getPasswdEntryFromUser();        break;
  237.     case '2':  entry = getPasswdEntryFromDataBase();    break;
  238.     case '3':  entry = getPasswdEntryInteractive(NULL);    break;
  239.     case 'q':  case 'Q':    exit(EXIT_FAILURE);
  240.     default:   continue;
  241.     }
  242.     break;
  243.     }
  244.     for (;;) {
  245.     while (parsePasswdEntry(entry, &passwdStruct) == 0) {
  246.         fprintf(stderr, "Entry is mangled, please correct it.\n");
  247.         c = '1';
  248.         entry = getPasswdEntryInteractive(&passwdStruct);
  249.     }
  250.     getString("", "Project    ", project);
  251.     for (;;) {
  252.         getString("", "Forward    ", forward);
  253.         if (*forward && strchr(forward, '@@') == NULL) {
  254.         fprintf(stderr,
  255.            "Improperly formed address, should be ``user@@machine''\n");
  256.         continue;
  257.         }
  258.         break;
  259.     }
  260.     dir = getHomeDir();
  261.     printPasswdEntry(&passwdStruct, dir);
  262.     if (strcmp(passwdStruct.pw_passwd,"*")==0) {
  263.         fprintf(stderr,"WARNING: passwd is '*' - login disabled\n");
  264.     }
  265.     if (yes("Is this correct?")) {
  266.         break;
  267.     }
  268.     entry = getPasswdEntryInteractive(&passwdStruct);
  269.     }
  270.     sprintf(real_homedir, "%s/%s", dir, passwdStruct.pw_name);
  271.     username = passwdStruct.pw_name;
  272.     insertPasswdEntry(&passwdStruct);
  273.     makeLinktoHomeDir(real_homedir, username);
  274.     if (create_ptmp_file == DONE) {
  275.  
  276.         if (makedb(PTMP_FILE)) {
  277.         (void)fprintf(stderr, "adduser: mkpasswd failed.\n");
  278.         cleanup(0);
  279.         }
  280.  
  281.         /*
  282.          * possible race; have to rename four files, and someone could slip
  283.          * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
  284.          * so that getpwent(3) can't slip in; the lock should never fail and
  285.          * it's unclear what to do if it does.  Rename ``ptmp'' last so that
  286.          * passwd/vipw/chpass can't slip in.
  287.          */
  288.         fend = strcpy(from, PTMP_FILE) + strlen(PTMP_FILE);
  289.         tend = strcpy(to, PASSWD_FILE) + strlen(PASSWD_FILE);
  290.         bcopy(".dir", fend, 5);
  291.         bcopy(".dir", tend, 5);
  292.         if ((fd = open(from, O_RDONLY, 0)) >= 0) {
  293.         (void)flock(fd, LOCK_EX);
  294.     }
  295.         /* here we go... */
  296.         (void)rename(from, to);
  297.         bcopy(".pag", fend, 5);
  298.         bcopy(".pag", tend, 5);
  299.         (void)rename(from, to);
  300.         bcopy(".orig", fend, 6);
  301.         (void)rename(PASSWD_FILE, PASSWD_BAK);
  302.         (void)rename(MASTER_PASSWD_FILE, MASTER_BAK);
  303.         (void)rename(from, PASSWD_FILE);
  304.         (void)rename(PTMP_FILE, MASTER_PASSWD_FILE);
  305.         /* done! */
  306.  
  307.     move_ptmp_to_passwd = DONE;
  308.     }
  309.     createHomeDirectory(real_homedir, username, project, forward,
  310.     passwdStruct.pw_uid, passwdStruct.pw_gid);
  311.     add2MailingList("sprite-users", username);
  312. #if 0    
  313.     if (yes("do you want to send mail?")) {
  314.     sendmsg(username);
  315.     }
  316. #endif    
  317.     printf("Done creating account for %s\n", username);
  318.     exit(EXIT_SUCCESS);
  319. }
  320.  
  321.  
  322. /*
  323.  *----------------------------------------------------------------------
  324.  *
  325.  * parseGecos --
  326.  *
  327.  *    Parse the gecos field of a passwd entry.
  328.  *
  329.  * Results:
  330.  *    Returns the next comma-sperated field.
  331.  *
  332.  * Side effects:
  333.  *    Overwrites the commas with null bytes.
  334.  *
  335.  *----------------------------------------------------------------------
  336.  */
  337.  
  338. static char *
  339. parseGecos(p)
  340.     char *p;
  341. {
  342.  
  343.     while (*p) {
  344.     if (*p++ == ',') {
  345.         p[-1] = '\0';
  346.         return p;
  347.     }
  348.     }
  349.     return p;
  350. }
  351.  
  352.  
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * printPasswdEntry --
  357.  *
  358.  *    Pick apart a passwd entry and print it out.
  359.  *
  360.  * Results:
  361.  *    None.
  362.  *
  363.  * Side effects:
  364.  *    Prints the passwd information to stdout.
  365.  *
  366.  *----------------------------------------------------------------------
  367.  */
  368. static void
  369. printPasswdEntry(pwd, dir)
  370.     CONST struct passwd *pwd;
  371.     CONST char *dir;
  372. {
  373.     CONST struct group *gwd;
  374.     char *group, *fullname, *office, *phone, *home_phone;
  375.     char *gecos;
  376.  
  377.     if ((gwd = getgrgid(pwd->pw_gid)) == NULL) {
  378.     group = "Invalid Group";
  379.     } else {
  380.     group = gwd->gr_name;
  381.     }
  382.     gecos = xmalloc(strlen(pwd->pw_gecos));
  383.     strcpy(gecos, pwd->pw_gecos);
  384.     fullname = gecos;
  385.     office = parseGecos(fullname);
  386.     phone = parseGecos(office);
  387.     home_phone = parseGecos(phone);
  388.     printf("\n");
  389.     printf("Login name: %s\n", pwd->pw_name);
  390.     printf("Full name:  %s\n", fullname);
  391.     printf("Passwd:     %s\n", pwd->pw_passwd);
  392.     printf("Uid:        %d\n", pwd->pw_uid);
  393.     printf("Group:      %s\n", group);
  394.     printf("Office:     %s\n", office);
  395.     printf("Phone       %s\n", phone);
  396.     printf("Home Phone: %s\n", home_phone);
  397.     printf("Directory:  %s -> %s/%s\n", pwd->pw_dir, dir, pwd->pw_name);
  398.     printf("Shell:      %s\n", pwd->pw_shell);
  399.     printf("Project:    %s\n", project);
  400.     printf("Forward:    %s\n", forward);
  401.     printf("\n");
  402.     free(gecos);
  403.     return;
  404. }
  405.  
  406. #if 0
  407.  
  408. /*
  409.  *----------------------------------------------------------------------
  410.  *
  411.  * sendmail --
  412.  *
  413.  *    Send a mail message.
  414.  *
  415.  * Results:
  416.  *    None.
  417.  *
  418.  * Side effects:
  419.  *    Mail is sent.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423. static void
  424. sendmsg(username)
  425.     CONST char *username;
  426. {
  427.     char buf[0x100];
  428.     CONST char *editor;
  429.     int tmp;
  430.  
  431.     if ((tmp = open(MAIL_TMP, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
  432.     fprintf(stderr, "Cannot open %s: %s\n", MAIL_TMP, strerror(errno));
  433.         return;
  434.     }
  435.     if (write(tmp, MAIL_MSG, strlen(MAIL_MSG)) != strlen(MAIL_MSG)) {
  436.     fprintf(stderr, "Error writing %s: %s\n", MAIL_TMP, strerror(errno));
  437.         return;
  438.     }
  439.     close(tmp);
  440.     if ((editor = getenv("EDITOR")) == 0) {
  441.     editor = "vi";
  442.     }
  443.     if (strcmp(editor, "mx") == 0) {
  444.     (void)sprintf(buf, "mx -D %s", MAIL_TMP);
  445.     } else {
  446.     (void)sprintf(buf, "%s %s", editor, MAIL_TMP);
  447.     }
  448.     if (system(buf)) {
  449.     fprintf(stderr, "Not sending mail: %s\n", strerror(errno));
  450.     } else if (yes("Do you want to mail the message?")) {
  451.     sprintf(buf, "mail %s -c %s -s \"Sprite account\" < %s",
  452.         username, whoami, MAIL_TMP);
  453.     if (system(buf)) {
  454.         fprintf(stderr, "Problem sending mail: %s\n", strerror(errno));
  455.     }
  456.     }
  457.     unlink(MAIL_TMP);
  458.     return;
  459. }
  460. #endif /* 0 */
  461.  
  462.  
  463. /*
  464.  *----------------------------------------------------------------------
  465.  *
  466.  * makeLinktoHomeDir --
  467.  *
  468.  *    Makes a link from /users/username to the real home directory.
  469.  *
  470.  * Results:
  471.  *    None.
  472.  *
  473.  * Side effects:
  474.  *    A symbolic link is created.
  475.  *
  476.  *----------------------------------------------------------------------
  477.  */
  478. static void
  479. makeLinktoHomeDir(homedir, username)
  480.     CONST char *homedir;
  481.     CONST char *username;
  482. {
  483.  
  484.     if (!strncmp(USER_DIR, homedir, strlen(USER_DIR))) {
  485.     return;
  486.     }
  487.     sprintf(sym_homedir, "%s/%s", USER_DIR, username);
  488.     if (symlink(homedir, sym_homedir)) {
  489.     if (errno != EEXIST) {
  490.         fprintf(stderr, "Cannot create link %s -> %s\n",
  491.         sym_homedir, homedir);
  492.     }
  493.     make_symlink = SKIP_THIS_STEP;
  494.     } else {
  495.     make_symlink = DONE;
  496.     }
  497.     return;
  498. }
  499.  
  500.  
  501. /*
  502.  *----------------------------------------------------------------------
  503.  *
  504.  * add2MailingList --
  505.  *
  506.  *    Adds a user to a mailing list.
  507.  *
  508.  * Results:
  509.  *    None.
  510.  *
  511.  * Side effects:
  512.  *    Modifies the sendmail aliases file.
  513.  *
  514.  *----------------------------------------------------------------------
  515.  */
  516. static void
  517. add2MailingList(list, name)
  518.     CONST char *list;
  519.     CONST char *name;
  520. {
  521.     char *expr;
  522.     int status;            /* exit status from subprocesses */
  523.     char logMsg[4096];        /* log message for "ci" */
  524.  
  525.     printf("Adding %s to \"%s\" mailing list\n", name, list);
  526.     sprintf(logMsg, "-madduser: add %s to \"%s\".", name, list);
  527.  
  528.     status = rcsCheckOut(ALIASES);
  529.     if (status < 0) {
  530.     cleanup(0);
  531.     /* NOTREACHED */
  532.     } else if (status != 0) {
  533.     goto error;
  534.     }
  535.  
  536.     /* 
  537.      * Edit a copy of the aliases file and then rename it to be the 
  538.      * real one. 
  539.      */
  540.     if (copy(ALIASES, ALIASES_TMP, 0644)) {
  541.     goto error;
  542.     }
  543.     expr = xmalloc(strlen(list) + strlen(name) + 20);
  544.     sprintf(expr, "/^%s:/s/, *$/, %s,/", list, name);
  545.     if (sed(ALIASES_TMP, expr, 0644)) {
  546.     fprintf(stderr, "Cannot change mail alias file\n");
  547.     free(expr);
  548.     goto error;
  549.     }
  550.     free(expr);
  551.  
  552.     /* XXX - error checking? */
  553.     unlink(ALIASES_BAK);
  554.     rename(ALIASES, ALIASES_BAK);
  555.     rename(ALIASES_TMP, ALIASES);
  556.  
  557.     /* 
  558.      * Check the aliases file back in.  If there's a problem, say that 
  559.      * we succeeded anyway (because we did edit the aliases).
  560.      */
  561.     status = rcsCheckIn(ALIASES, logMsg);
  562.     if (status == 0) {
  563.     printf("Added %s to %s mailing list.\n", name, list);
  564.     } else {
  565.     fprintf(stderr, "\nPlease check the aliases file.\n");
  566.     fprintf(stderr, "(Make sure that `%s' was added to `%s'\n",
  567.            name, list);
  568.     fprintf(stderr, "and that the file was checked in.)\n\n");
  569.     }
  570.     edit_mailaliases_file = DONE;
  571.     return;
  572.  
  573.  error:
  574.     fprintf(stderr, "\nWarning: unable to add `%s' to the list `%s'.\n",
  575.         name, list);
  576.     fprintf(stderr, "You'll have to edit the aliases file by hand.\n\n");
  577.     return;
  578. }
  579.  
  580.  
  581. /*
  582.  *----------------------------------------------------------------------
  583.  *
  584.  * sed --
  585.  *
  586.  *    Filter a file through sed.
  587.  *
  588.  * Results:
  589.  *    Returns the exit status from sed.  0 if successful,
  590.  *      non-zero if there were problems.
  591.  *
  592.  * Side effects:
  593.  *    File is changed, a backup file is created.
  594.  *
  595.  *----------------------------------------------------------------------
  596.  */
  597. static int
  598. sed(filename, expr, mode)
  599.     CONST char *filename;
  600.     CONST char *expr;
  601.     int mode;
  602. {
  603.     char tmp[MAXPATHLEN];
  604.     char old[MAXPATHLEN];
  605.     int child;
  606.     int w;
  607.     int in, out;
  608.     union wait ws;
  609.  
  610.     sprintf(tmp, "%s.adduser", filename);
  611.     sprintf(old, "%s.old", filename);
  612.     if ((in = open(filename, O_RDONLY)) < 0) {
  613.     fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
  614.     return 1;
  615.     }
  616.     if ((out = open(tmp, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) {
  617.     fprintf(stderr, "Cannot open %s: %s\n", tmp, strerror(errno));
  618.         return 1;
  619.     }
  620.     switch (child = fork()) {
  621.  
  622.     case -1:
  623.     fprintf(stderr, "Fork failed: %s\n", strerror(errno));
  624.     cleanup(0);
  625.  
  626.     case 0:
  627.     dup2(in, 0);
  628.     dup2(out, 1);
  629.     execlp("sed", "sed", expr, NULL);
  630.     fprintf(stderr, "Cannot exec sed: %s\n", strerror(errno));
  631.     exit(EXIT_FAILURE);
  632.  
  633.     default:
  634.     while ((w = wait(&ws)) > 0 && w != child) {
  635.         continue;
  636.     }
  637.     if (ws.w_retcode) {
  638.         return ws.w_retcode;
  639.     }
  640.     break;
  641.     }
  642.     unlink(old);
  643.     if (rename(filename, old)) {
  644.     fprintf(stderr, "Cannot rename %s as %s: %s\n",
  645.         filename, old, strerror(errno));
  646.     return 1;
  647.     }
  648.     if (rename(tmp, filename)) {
  649.     fprintf(stderr, "Cannot rename %s as %s: %s\n",
  650.         tmp, filename, strerror(errno));
  651.     return 1;
  652.     }
  653.     unlink(old);
  654.     return 0;
  655. }
  656.  
  657.  
  658. /*
  659.  *----------------------------------------------------------------------
  660.  *
  661.  * createHomeDirectory --
  662.  *
  663.  *    Create a directory and copy the prototype new user directory
  664.  *      there.
  665.  *
  666.  * Results:
  667.  *    None.
  668.  *
  669.  * Side effects:
  670.  *    Creates directory.
  671.  *
  672.  *----------------------------------------------------------------------
  673.  */
  674. static void
  675. createHomeDirectory(dir, username, project, forward, uid, gid)
  676.     CONST char *dir;
  677.     CONST char *username;
  678.     CONST char *forward;
  679.     CONST char *project;
  680.     int uid;
  681.     int gid;
  682. {
  683.     int child;
  684.     int w;
  685.     char cshrc[MAXPATHLEN];
  686.     char expr[BUFFER_SIZE + 20];
  687.     char projf[MAXPATHLEN];
  688.     char forwf[MAXPATHLEN];
  689.     union wait ws;
  690.     int fd;
  691.  
  692.     printf("Creating home directory: %s\n", dir);
  693.     if (mkdir(dir, 0775) != 0) {
  694.     fprintf(stderr, "Cannot create %s: %s\n", dir, strerror(errno));
  695.     if (yes("Do you want to continue?")) {
  696.         create_home_dir  = SKIP_THIS_STEP;
  697.         return;
  698.     } else {
  699.         cleanup(0);
  700.     }
  701.     }
  702.     create_home_dir = DONE;
  703. #ifndef TEST
  704.     if (chown(dir, uid, gid)) {
  705.     fprintf(stderr, "Can't change ownership of %s: %s\n",
  706.         dir, strerror(errno));
  707.     cleanup(0);
  708.     }
  709. #endif
  710.     switch (child = fork()) {
  711.  
  712.     case -1:
  713.     fprintf(stderr, "Fork failed: %s\n", strerror(errno));
  714.     cleanup(0);
  715.  
  716.     case 0:
  717. #ifdef TEST
  718.     execlp("update", "update", NEWUSER_DIR, dir, NULL);
  719. #else
  720.     execlp("update", "update", "-o", username, NEWUSER_DIR, dir, NULL);
  721. #endif
  722.     fprintf(stderr, "Cannot exec update\n");
  723.     cleanup(0);
  724.  
  725.     default:
  726.     while ((w = wait(&ws)) > 0 && w != child) {
  727.         continue;
  728.     }
  729.     if (ws.w_retcode) {
  730.         if (yes("Update failed, do you want to continue?") == 0) {
  731.         cleanup(0);
  732.         }
  733.     }
  734.     break;
  735.     }
  736.     sprintf(cshrc, "%s/.cshrc", dir);
  737.     sprintf(expr, "s/newuser/%s/g", username);
  738.     if (sed(cshrc, expr, 0644)) {
  739.     fprintf(stderr, "Cannot edit %s\n", cshrc);
  740.     }
  741. #ifndef TEST
  742.     if (chown(cshrc, uid, gid)) {
  743.     fprintf(stderr, "Warning: Can't change ownership of %s: %s\n",
  744.         cshrc, strerror(errno));
  745.     }
  746. #endif
  747.     sprintf(projf, "%s/.project", dir);
  748.     if ((fd = open(projf, O_WRONLY|O_TRUNC|O_CREAT, 0644)) < 0) {
  749.     fprintf(stderr, "Cannot open %s: %s\n", projf, strerror(errno));
  750.     return;
  751.     }
  752.     strcat(project, "\n");
  753.     if (write(fd, project, strlen(project)) != strlen(project)) {
  754.     fprintf(stderr, "Error writing %s: %s\n", projf, strerror(errno));
  755.     }
  756.     close(fd);
  757.     sprintf(forwf, "%s/.forward", dir);
  758.     if (*forward) {
  759.     if ((fd = open(forwf, O_WRONLY|O_TRUNC|O_CREAT, 0644)) < 0) {
  760.         fprintf(stderr, "Cannot open %s: %s\n", forwf, strerror(errno));
  761.         return;
  762.     }
  763.     strcat(forward, "\n");
  764.     if (write(fd, forward, strlen(forward)) != strlen(forward)) {
  765.         fprintf(stderr, "Error writing %s: %s\n", forwf, strerror(errno));
  766.     }
  767.     } else {
  768.     unlink(forwf);
  769.     }
  770.     close(fd);
  771.     return;
  772. }
  773.  
  774.  
  775. /*
  776.  *----------------------------------------------------------------------
  777.  *
  778.  *  insertPasswdEntry --
  779.  *
  780.  *    Inserts a passwd entry into the password file.
  781.  *
  782.  * Results:
  783.  *    None.
  784.  *
  785.  * Side effects:
  786.  *    Modifies /etc/passwd.  Creates a backup file.
  787.  *
  788.  *----------------------------------------------------------------------
  789.  */
  790.  
  791. static void
  792. insertPasswdEntry(newpwd)
  793.     CONST struct passwd *newpwd;
  794. {
  795.     int fd;
  796.     FILE *ptmp;
  797.     struct passwd *pwd;
  798.     char buf1[16], buf2[16];
  799.  
  800.     if ((fd = open(PTMP_FILE, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
  801.     fprintf(stderr, "Cannot open %s: %s\n", PTMP_FILE, strerror(errno));
  802.     cleanup(0);
  803.     }
  804.     ptmp = fdopen(fd, "w");
  805. #ifndef TEST
  806.     if (getgrnam("wheel") == (struct group *)NULL) {
  807.     fprintf(stderr,"Warning: no wheel group\n");
  808.     } else {
  809.     fchown(fd, -1, getgrnam("wheel")->gr_gid);
  810.     }
  811. #endif
  812.  
  813.     create_ptmp_file = DONE;
  814.     while ((pwd = getpwent()) != NULL) {
  815.     if (strcmp(pwd->pw_name, newpwd->pw_name) == 0) {
  816.         fprintf(stderr,
  817.         "There is already an entry in /etc/passwd for %s\n",
  818.         newpwd->pw_name);
  819.         if (yes("Do you want to replace it?")) {
  820.         continue;
  821.         } else if (yes("Do you want to continue?")) {
  822.         unlink(PTMP_FILE);
  823.         create_ptmp_file = SKIP_THIS_STEP;
  824.         printf("%s left unchanged\n", MASTER_PASSWD_FILE);
  825.         return;
  826.         } else {
  827.         cleanup(0);
  828.         }
  829.     }
  830.     if (pwd->pw_change==0) {
  831.         *buf1 = '\0';
  832.     } else {
  833.         sprintf(buf1,"%l",pwd->pw_change);
  834.     }
  835.     if (pwd->pw_expire==0) {
  836.         *buf2 = '\0';
  837.     } else {
  838.         sprintf(buf2,"%l",pwd->pw_expire);
  839.     }
  840.     fprintf(ptmp, "%s:%s:%d:%d:%s:%s:%s:%s:%s:%s\n",
  841.         pwd->pw_name,
  842.         pwd->pw_passwd,
  843.         pwd->pw_uid,
  844.         pwd->pw_gid,
  845.         pwd->pw_class,
  846.         buf1,
  847.         buf2,
  848.         pwd->pw_gecos,
  849.         pwd->pw_dir,
  850.         pwd->pw_shell);
  851.     }
  852.     endpwent();
  853.     if (newpwd->pw_change==0) {
  854.     *buf1 = '\0';
  855.     } else {
  856.     sprintf(buf1,"%l",newpwd->pw_change);
  857.     }
  858.     if (newpwd->pw_expire==0) {
  859.     *buf2 = '\0';
  860.     } else {
  861.     sprintf(buf2,"%l",newpwd->pw_expire);
  862.     }
  863.     fprintf(ptmp, "%s:%s:%d:%d:%s:%s:%s:%s:%s:%s\n",
  864.     newpwd->pw_name,
  865.     newpwd->pw_passwd,
  866.     newpwd->pw_uid,
  867.     newpwd->pw_gid,
  868.     newpwd->pw_class,
  869.     buf1,
  870.     buf2,
  871.     newpwd->pw_gecos,
  872.     newpwd->pw_dir,
  873.     newpwd->pw_shell);
  874.      fclose(ptmp);
  875.      return;
  876. }
  877.  
  878.  
  879. /*
  880.  *----------------------------------------------------------------------
  881.  *
  882.  * getPasswdEntryFromUser --
  883.  *
  884.  *    Prompt the user for a string.
  885.  *
  886.  * Results:
  887.  *    Returns the string.
  888.  *
  889.  * Side effects:
  890.  *    None.
  891.  *
  892.  *----------------------------------------------------------------------
  893.  */
  894. static char *
  895. getPasswdEntryFromUser()
  896. {
  897.     static char buf[BUFFER_SIZE];
  898.  
  899.     getString("", "Enter the /etc/passwd line", buf);
  900.     return buf;
  901. }
  902.  
  903.  
  904. /*
  905.  *----------------------------------------------------------------------
  906.  *
  907.  * getPasswdEntryFromDataBase --
  908.  *
  909.  *    Gets a passwd file entry from the ucb global database.
  910.  *
  911.  * Results:
  912.  *    Returns then entry.
  913.  *
  914.  * Side effects:
  915.  *    None.
  916.  *
  917.  *----------------------------------------------------------------------
  918.  */
  919. static char *
  920. getPasswdEntryFromDataBase()    
  921. {
  922.     static char lastname[BUFFER_SIZE];
  923.     static char group[BUFFER_SIZE];
  924.     int child;
  925.     int pipefd[2];
  926.     int w;
  927.     static char entry[BUFFER_SIZE];
  928.     union wait ws;
  929.  
  930.     for (;;) {
  931.     getString(":", "Enter user's last name", lastname);
  932.     for (;;) {
  933.         getString(":", "Enter user's group", group);
  934.         if (getgrnam(group)) {
  935.         break;
  936.         }
  937.         fprintf(stderr,
  938.         "%s is not a valid group (not in /etc/group).\n", group);
  939.         fprintf(stderr, "Pleas try again\n");
  940.     }
  941.     printf("lastname is %s, group is %s\n", lastname, group);
  942.     if (yes("Is this correct?")) {
  943.         break;
  944.     }
  945.     }
  946.     printf("Fetching passwd entry from database on %s.\n", DATABASE_HOST);
  947.     printf("This will take a minute or two.  Please be patient....\n");
  948.     pipe(pipefd);
  949.     switch (child = fork()) {
  950.  
  951.     case -1:
  952.     fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
  953.     exit(EXIT_FAILURE);
  954.  
  955.     case 0: /* child */
  956.         close(pipefd[0]);
  957.     dup2(pipefd[1], 1);
  958.     execlp("rsh", "rsh", "allspice", "-l", "root", "rsh", DATABASE_HOST,
  959.            "-l", "account", "=bin/mkpwent", USER_DIR, lastname, group,
  960.            NULL);
  961.     fprintf(stderr, "Cannot exec rsh: %s\n", strerror(errno));
  962.     exit(EXIT_FAILURE);
  963.  
  964.     default: /* parent */
  965.     close(pipefd[1]);
  966.         if ((w = read(pipefd[0], entry, sizeof(entry))) < 0) {
  967.         fprintf(stderr, "Read from pipe failed: %s\n", strerror(errno));
  968.         exit(EXIT_FAILURE);
  969.     }
  970.     if (entry[strlen(entry) - 1] == '\n') {
  971.         entry[strlen(entry) - 1] = '\0';
  972.     }
  973.     close(pipefd[0]);
  974.  
  975.     while ((w = wait(&ws)) > 0 && w != child) {
  976.         continue;
  977.     }
  978.     if (ws.w_retcode) {
  979.         fprintf(stderr, "Could't fetch entry from %s\n", DATABASE_HOST);
  980.         fprintf(stderr, "Make sure your machine is listed in /.rhosts\n");
  981.         cleanup(0);
  982.     }
  983.     break;
  984.     }
  985.     return entry;
  986. }
  987.  
  988.  
  989. /*
  990.  *----------------------------------------------------------------------
  991.  *
  992.  * getPasswdEntryInteractive --
  993.  *
  994.  *    description.
  995.  *
  996.  * Results:
  997.  *    None.
  998.  *
  999.  * Side effects:
  1000.  *    None.
  1001.  *
  1002.  *----------------------------------------------------------------------
  1003.  */
  1004. static char *
  1005. getPasswdEntryInteractive(pwd)
  1006.     CONST struct passwd *pwd;
  1007. {
  1008.     static char username[BUFFER_SIZE];
  1009.     static char userid[BUFFER_SIZE];
  1010.     static char groupid[BUFFER_SIZE];
  1011.     static char fullname[BUFFER_SIZE];
  1012.     static char office[BUFFER_SIZE];
  1013.     static char phone[BUFFER_SIZE];
  1014.     static char home_phone[BUFFER_SIZE];
  1015.     static char info[BUFFER_SIZE];
  1016.     static char entry[BUFFER_SIZE];
  1017.     static char passwd[BUFFER_SIZE];
  1018.  
  1019.     char *shell;
  1020.     struct group *gp;
  1021.  
  1022.     if (pwd) {
  1023.     char *gecos, *t1, *t2;
  1024.  
  1025.     strcpy(username, pwd->pw_name);
  1026.     strcpy(passwd, pwd->pw_passwd);
  1027.     sprintf(userid, "%d", pwd->pw_uid);
  1028.     sprintf(groupid, "%d", pwd->pw_gid);
  1029.     gecos = xmalloc(strlen(pwd->pw_gecos));
  1030.     strcpy(gecos, pwd->pw_gecos);
  1031.     t1 = parseGecos(gecos);
  1032.     strcpy(fullname, gecos);
  1033.     t2 = parseGecos(t1);
  1034.     strcpy(office, t1);
  1035.     t1 = parseGecos(t2);
  1036.     strcpy(phone, t2);
  1037.     strcpy(home_phone, t1);
  1038.     }
  1039.     getString(":", "new users login name", username);
  1040.     getPasswd(passwd);
  1041.     getNumber("user id", userid);
  1042.     for (;;) {
  1043.     getString(":", "group id", groupid);
  1044.     if (isdigit(*groupid)) {
  1045.         gp = getgrgid(atoi(groupid));
  1046.     } else {
  1047.         gp = getgrnam(groupid);
  1048.     }
  1049.     if (gp == NULL) {
  1050.         fprintf(stderr, "%s is not a valid group\n", groupid);
  1051.         fprintf(stderr, "Please try again\n");
  1052.         continue;
  1053.     }
  1054.     break;
  1055.     }
  1056.     getString(":,", "full name", fullname);
  1057.     getString(":,", "office", office);
  1058.     getString(":,", "work phone number", phone);
  1059.     getString(",:", "home phone number", home_phone);
  1060.     shell = getShell();
  1061.     sprintf(info, "%s,%s,%s,%s", fullname, office, phone, home_phone);
  1062.     sprintf(entry, "%s:%s:%s:%d:%s:%s/%s:%s",
  1063.         username, passwd, userid, gp->gr_gid, info, USER_DIR, username, shell);
  1064.     return entry;
  1065. }
  1066.  
  1067. static char *
  1068. getHomeDir()
  1069. {
  1070.     static char dir[BUFFER_SIZE];
  1071.     int c;
  1072.  
  1073.     printf("Where would you like to put the home directory?\n");
  1074.     printf("Enter 1 for /user1    (misc accounts)\n");
  1075.     printf("Enter 2 for /user6    (spriters)\n");
  1076.     printf("Enter 3 for /user3    (on cory cluster)\n");
  1077.     printf("Enter 4 for /user4    (raid hardware people)\n");
  1078.     printf("Enter 5 for /pcs      (mic group)\n");
  1079.     printf("Enter 6 for /postdev  (postgres people)\n");
  1080.     printf("Enter 7 for somewhere else\n");
  1081.     for (;;) {
  1082.         printf("Please choose one of the above: ");
  1083.     c = raw_getchar();
  1084.     printf("\n");
  1085.     switch (c) {
  1086.  
  1087.     case '1':
  1088.         strcpy(dir, "/user1");
  1089.         break;
  1090.  
  1091.     case '2': 
  1092.         strcpy(dir, "/user6");
  1093.         break;
  1094.  
  1095.     case '3':
  1096.         strcpy(dir, "/user3");
  1097.         break;
  1098.  
  1099.     case '4':
  1100.         strcpy(dir, "/user4");
  1101.         break;
  1102.  
  1103.     case '5':
  1104.         strcpy(dir, "/pcs");
  1105.         break;
  1106.  
  1107.     case '6':
  1108.         strcpy(dir, "/postdev");
  1109.         break;
  1110.  
  1111.     case '7':
  1112.         for (;;) {
  1113.         getString("*?[]", "Please enter the directory", dir);
  1114.         if (*dir != '/') {
  1115.             fprintf(stderr, "Path must start at root.");
  1116.             continue;
  1117.         }
  1118.         if (strlen(dir) > 1 && dir[strlen(dir) - 1] == '/') {
  1119.             dir[strlen(dir) - 1] = '\0';
  1120.         }
  1121.         break;
  1122.         }
  1123.         break;
  1124.  
  1125.     default:
  1126.         continue;
  1127.     }
  1128.     break;
  1129.     }
  1130.     return dir;
  1131. }
  1132.  
  1133. static char *
  1134. pwskip(p)
  1135.     char *p;
  1136. {
  1137.     while (*p && *p != ':') {
  1138.     ++p;
  1139.     }
  1140.     if (*p) {
  1141.     *p++ = 0;
  1142.     }
  1143.     return p;
  1144. }
  1145.  
  1146. static int
  1147. parsePasswdEntry(p, ps)
  1148.     char *p;
  1149.     struct passwd *ps;
  1150. {
  1151.     char *uid, *gid;
  1152.     static char homedir[MAXPATHLEN];
  1153.  
  1154.     ps->pw_name = p;
  1155.     p = pwskip(p);
  1156.     ps->pw_passwd = p;
  1157.     uid = p = pwskip(p);
  1158.     ps->pw_uid = atoi(p);
  1159.     gid = p = pwskip(p);
  1160.     ps->pw_gid = atoi(p);
  1161.     p = pwskip(p);
  1162.     ps->pw_class = "";
  1163.     ps->pw_change = 0;
  1164.     ps->pw_expire = 0;
  1165.     ps->pw_gecos = p;
  1166.     p = pwskip(p);
  1167.     ps->pw_dir = p;
  1168.     p = pwskip(p);
  1169.     ps->pw_shell = p;
  1170.     if (strlen(ps->pw_name) == 0) {
  1171.     fprintf(stderr, "Null username\n");
  1172.     return 0;
  1173.     }
  1174.     if (*ps->pw_passwd != '*' && strlen(ps->pw_passwd) != 13) {
  1175.     fprintf(stderr, "Invalid encrypted password: \"%s\"\n", ps->pw_passwd);
  1176.     return 0;
  1177.     }
  1178. #if 0    
  1179.     while (strlen(ps->pw_passwd) != 13) {
  1180.     if (*ps->pw_passwd == '\0' || strcmp(ps->pw_passwd, "*") == 0) {
  1181.         printf("Please enter a password\n");
  1182.         ps->pw_passwd = getPasswd();
  1183.         continue;
  1184.     }
  1185.     fprintf(stderr, "Invalid encrypted passwd\n");
  1186.     return 0;
  1187.     }
  1188. #endif
  1189.     if (checkNumber(uid) == 0) {
  1190.     fprintf(stderr, "Non digit in uid field\n");
  1191.     return 0;
  1192.     }
  1193.     if (checkNumber(gid) == 0) {
  1194.     fprintf(stderr, "Non digit in gid field\n");
  1195.     return 0;
  1196.     }
  1197.     sprintf(homedir, "%s/%s", USER_DIR, ps->pw_name);
  1198.     ps->pw_dir = homedir;
  1199.     if (*ps->pw_shell != '/') {
  1200.     fprintf(stderr, "Bad shell: %s\n", ps->pw_shell);
  1201.     return 0;
  1202.     }
  1203.     return 1;
  1204. }
  1205.  
  1206. static char *
  1207. xmalloc(n)
  1208.     int n;
  1209. {
  1210.     char *p;
  1211.  
  1212.     if ((p = malloc(n)) == NULL) {
  1213.     fprintf(stderr, "Malloc failed: %s\n", strerror(errno));
  1214.     cleanup(0);
  1215.     }
  1216.     return p;
  1217. }
  1218.  
  1219.  
  1220. /*
  1221.  *----------------------------------------------------------------------
  1222.  *
  1223.  * copy --
  1224.  *
  1225.  *    Create a copy of a file.
  1226.  *
  1227.  * Results:
  1228.  *    Returns 0 if there was no error, non-zero if there was an error.
  1229.  *
  1230.  * Side effects:
  1231.  *    None.
  1232.  *
  1233.  *----------------------------------------------------------------------
  1234.  */
  1235.  
  1236. static int
  1237. copy(from, to, mode)
  1238.     CONST char *from;
  1239.     CONST char *to;
  1240.     int mode;            /* the permissions for the new file */
  1241. {
  1242.     char *buf;
  1243.     int in, out;
  1244.     long in_len;
  1245.  
  1246.     if ((in = open(from, O_RDONLY)) < 0) {
  1247.     fprintf(stderr, "Cannot open %s: %s\n", from, strerror(errno));
  1248.     return 1;
  1249.     }
  1250.     if ((out = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0) {
  1251.     fprintf(stderr, "Cannot open %s: %s\n", to, strerror(errno));
  1252.     return 1;
  1253.     }
  1254.     in_len = lseek(in, 0, L_XTND);
  1255.     lseek(in, 0, L_SET);
  1256.     buf = xmalloc(in_len);
  1257.     if (read(in, buf, in_len) != in_len) {
  1258.     fprintf(stderr, "Error reading %s: %s\n", to, strerror(errno));
  1259.     return 1;
  1260.     }
  1261.     close(in);
  1262.     if (write(out, buf, in_len) != in_len) {
  1263.     fprintf(stderr, "Error writing %s: %s\n", to, strerror(errno));
  1264.     return 1;
  1265.     }
  1266.     free(buf);
  1267.     return 0;
  1268. }
  1269.  
  1270. static void    
  1271. cleanup(sig)
  1272.     int sig;            /* signal number (ignored) */
  1273. {
  1274.     fprintf(stderr, "\nCleaning up ...\n");
  1275.     if (move_ptmp_to_passwd == DONE) {
  1276.     if (rename(MASTER_PASSWD_FILE, PTMP_FILE)) {
  1277.         fprintf(stderr, "Cannot rename %s to %s: %s\n",
  1278.         MASTER_PASSWD_FILE, PTMP_FILE, strerror(errno));
  1279.     } else if (rename(MASTER_BAK, MASTER_PASSWD_FILE)) {
  1280.         fprintf(stderr, "Cannot rename %s to %s: %s\n",
  1281.         MASTER_BAK, MASTER_PASSWD_FILE, strerror(errno));
  1282.     } else if (rename(PASSWD_BAK, PASSWD_FILE)) {
  1283.         fprintf(stderr, "Cannot rename %s to %s: %s\n",
  1284.         PASSWD_BAK, PASSWD_FILE, strerror(errno));
  1285.     } else {
  1286.         unlink(PTMP_FILE);
  1287.     }
  1288.     } else if (create_ptmp_file == DONE) {
  1289.     if (unlink(PTMP_FILE)) {
  1290.         fprintf(stderr, "Cannot unlink %s: %s\n", PTMP_FILE,
  1291.             strerror(errno));
  1292.     }
  1293.     }
  1294.     if (edit_mailaliases_file == DONE) {
  1295.     if (unlink(ALIASES_TMP)) {
  1296.         fprintf(stderr, "Cannot unlink %s: %s\n",
  1297.         ALIASES_TMP, strerror(errno));
  1298.     }
  1299.     }
  1300.     if (create_home_dir == DONE) {
  1301.     fprintf(stderr, "Deleteing %s/* ...\n", real_homedir);
  1302.     if (fork() == 0) {
  1303.         execlp("rm", "rm", "-rf", real_homedir, NULL);
  1304.     }
  1305.     }
  1306.     if (make_symlink == DONE) {
  1307.     if (unlink(sym_homedir)) {
  1308.         fprintf(stderr, "Cannot unlink %s: %s\n",
  1309.         sym_homedir, strerror(errno));
  1310.     }
  1311.     }
  1312.     exit(EXIT_FAILURE);
  1313. }
  1314.  
  1315. @
  1316.  
  1317.  
  1318. 1.12
  1319. log
  1320. @Put in a warning for an account created with '*' password.
  1321. @
  1322. text
  1323. @d20 1
  1324. a20 1
  1325. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.11 91/10/10 10:06:58 jhh Exp $";
  1326. d348 1
  1327. a348 1
  1328.     if ((tmp = open(MAIL_TMP, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
  1329. d457 1
  1330. a457 1
  1331.     if (copy(ALIASES, ALIASES_TMP, 0666)) {
  1332. d462 1
  1333. a462 1
  1334.     if (sed(ALIASES_TMP, expr, 0666)) {
  1335. d655 1
  1336. a655 1
  1337.     if (sed(cshrc, expr, 0664)) {
  1338. d717 1
  1339. a717 1
  1340.     if ((fd = open(PTMP_FILE, O_RDWR|O_CREAT|O_EXCL, 0660)) < 0) {
  1341. d1136 17
  1342. d1157 1
  1343. a1157 1
  1344.     int mode;
  1345. @
  1346.  
  1347.  
  1348. 1.11
  1349. log
  1350. @created bogus symbolic link if the home directory was supposed
  1351. to be in /users
  1352. @
  1353. text
  1354. @d20 1
  1355. a20 1
  1356. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.10 91/06/10 12:07:34 kupfer Exp Locker: jhh $";
  1357. d179 3
  1358. @
  1359.  
  1360.  
  1361. 1.10
  1362. log
  1363. @Set the real uid to root early on, rather than trying to figure out
  1364. which subprocesses (e.g., rsh) need to have real uid == effective uid.
  1365. @
  1366. text
  1367. @d20 1
  1368. a20 1
  1369. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.9 91/06/04 16:52:43 kupfer Exp Locker: kupfer $";
  1370. d398 3
  1371. @
  1372.  
  1373.  
  1374. 1.9
  1375. log
  1376. @Make sure the invoking user is in the wheel group.
  1377. @
  1378. text
  1379. @d20 1
  1380. a20 1
  1381. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.8 91/06/03 17:16:19 kupfer Exp Locker: kupfer $";
  1382. d138 1
  1383. a138 3
  1384.      * Verify that we're running as root, so as to avoid unpleasant 
  1385.      * surprises later.  Because the program is installed setuid, make 
  1386.      * sure that the invoking user is in the wheel group.
  1387. @
  1388.  
  1389.  
  1390. 1.8
  1391. log
  1392. @More code shared with deleteuser.  Don't try to edit the aliases file
  1393. if it couldn't be checked out.  Lint.  Better support for testing.
  1394. Give an RCS log message when checking in the aliases file.  
  1395. /user2 -> /user6.
  1396. @
  1397. text
  1398. @d20 1
  1399. a20 1
  1400. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.7 91/05/29 13:39:45 kupfer Exp Locker: kupfer $";
  1401. d137 6
  1402. a142 5
  1403.     if (setreuid(0, 0)) {
  1404.     fprintf(stderr, "Cannot set uid to root: %s\n", strerror(errno));
  1405.     fprintf(stderr, "This program must be installed setuid.\n");
  1406.     exit(EXIT_FAILURE);
  1407.     }
  1408. @
  1409.  
  1410.  
  1411. 1.7
  1412. log
  1413. @/mic -> /pcs.
  1414. @
  1415. text
  1416. @d20 1
  1417. a20 1
  1418. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.6 90/12/19 16:42:32 kupfer Exp Locker: kupfer $";
  1419. d23 9
  1420. d35 1
  1421. a35 4
  1422. #include <pwd.h>
  1423. #include <grp.h>
  1424. #include <signal.h>
  1425. #include <errno.h>
  1426. a36 1
  1427. #include <sys/file.h>
  1428. d38 1
  1429. d40 1
  1430. a40 5
  1431. #include <assert.h>
  1432.  
  1433. #ifndef __STDC__
  1434. #define const
  1435. #endif
  1436. d42 2
  1437. a43 14
  1438. extern int errno;
  1439. extern char *getPasswd();
  1440. extern char *getShell();
  1441.  
  1442. #define BUFFER_SIZE         0x100
  1443. #define USER_DIR            "/users"
  1444. #define NEWUSER_DIR         "/user1/newuser"
  1445.  
  1446. #define PASSWD_BAK          "/etc/passwd.adduser.BAK"
  1447. #define MASTER_BAK          "/etc/master.adduser.BAK"
  1448. #define MAIL_ALIASES        "/sprite/lib/sendmail/aliases"
  1449. #define MAIL_ALIASES_TMP    "/sprite/lib/sendmail/aliases.adduser.tmp"
  1450. #define MAIL_ALIASES_BAK    "/sprite/lib/sendmail/aliases.adduser.BAK"
  1451. #define MAIL_TMP            "/tmp/mail.adduser"
  1452. d46 1
  1453. a46 1
  1454. #define DATABASE_HOST        "thalm"
  1455. d48 3
  1456. a50 1
  1457. #define MAIL_MSG            mail_message
  1458. d52 1
  1459. a52 5
  1460. #ifdef __STDC__
  1461. extern void getString(const char *forbid, const char *prompt, char *buf);
  1462. #else
  1463. extern void getString();
  1464. #endif
  1465. d54 1
  1466. a54 1
  1467. static const char mail_message[] = "\
  1468. d59 1
  1469. a60 1
  1470. static struct sgttyb sgtty_buf;
  1471. d63 18
  1472. a80 40
  1473. #ifdef __STDC__
  1474. static void add2MailingList(const char *list, const char *name);
  1475. static void createHomeDirectory(const char *dir, const char *username,
  1476.            const char *project, const char *forward, int uid, int gid);
  1477. static void insertPasswdEntry(const struct passwd *newpw);
  1478. static char *getPasswdEntryFromUser(void);
  1479. static char *getPasswdEntryFromDataBase(void);
  1480. static char *getPasswdEntryInteractive(const struct passwd *pwd);
  1481. static void deletePasswdEntry(const char *name);
  1482. static char *getHomeDir(void);
  1483. static int  parsePasswdEntry(char *p, struct passwd *ps);
  1484. static int  sed(const char *filename, const char *expr, int mode);
  1485. static void cleanup(void);
  1486. static int  copy(const char *from, const char *to, int mode);
  1487. static char *xmalloc(int n);
  1488. static void makeLinktoHomeDir(const char *homedir, const char *username);
  1489. static void sendmsg(const char *username);
  1490. static void printPasswdEntry(const struct passwd *pwd, const char *dir);
  1491. static int  rcsCheckOut(char *file);
  1492. static int  rcsCheckIn(char *file);
  1493. #else
  1494. static void add2MailingList();
  1495. static void createHomeDirectory();
  1496. static void insertPasswdEntry();
  1497. static char *getPasswdEntryFromUser();
  1498. static char *getPasswdEntryFromDataBase();
  1499. static char *getPasswdEntryInteractive();
  1500. static void deletePasswdEntry();
  1501. static char *getHomeDir();
  1502. static int  parsePasswdEntry();
  1503. static int  sed();
  1504. static void cleanup();
  1505. static int  copy();
  1506. static char *xmalloc();
  1507. static void makeLinktoHomeDir();
  1508. static void sendmsg();
  1509. static void printPasswdEntry();
  1510. static int  rcsCheckOut();
  1511. static int  rcsCheckIn();
  1512. #endif
  1513. a124 1
  1514.     FILE *fp;
  1515. d136 1
  1516. d142 1
  1517. d191 3
  1518. a193 3
  1519.         if (makedb(_PATH_PTMP)) {
  1520.                 (void)fprintf(stderr, "vipw: mkpasswd failed; ");
  1521.         cleanup();
  1522. d203 2
  1523. a204 2
  1524.         fend = strcpy(from, _PATH_PTMP) + strlen(_PATH_PTMP);
  1525.         tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
  1526. d207 3
  1527. a209 2
  1528.         if ((fd = open(from, O_RDONLY, 0)) >= 0)
  1529.                 (void)flock(fd, LOCK_EX);
  1530. d216 4
  1531. a219 4
  1532.         (void)rename(_PATH_PASSWD, PASSWD_BAK);
  1533.         (void)rename(_PATH_MASTERPASSWD, MASTER_BAK);
  1534.         (void)rename(from, _PATH_PASSWD);
  1535.         (void)rename(_PATH_PTMP, _PATH_MASTERPASSWD);
  1536. d267 1
  1537. a267 1
  1538.  
  1539. d285 2
  1540. a286 2
  1541.     const struct passwd *pwd;
  1542.     const char *dir;
  1543. d288 1
  1544. a288 1
  1545.     const struct group *gwd;
  1546. d321 2
  1547. d340 1
  1548. a340 1
  1549.     const char *username;
  1550. d343 1
  1551. a343 1
  1552.     const char *editor;
  1553. d375 1
  1554. d377 1
  1555. d395 2
  1556. a396 2
  1557.     const char *homedir;
  1558.     const char *username;
  1559. d412 1
  1560. d430 2
  1561. a431 2
  1562.     const char *list;
  1563.     const char *name;
  1564. a432 2
  1565.     char s[BUFFER_SIZE];
  1566.     int pipeFd[2];
  1567. d434 2
  1568. d438 8
  1569. a445 3
  1570.     if (chdir("/sprite/lib/sendmail")) {
  1571.     fprintf(stderr, "Cannot chdir to %s\n", "/sprite/lib/sendmail");
  1572.     exit(EXIT_FAILURE);
  1573. d447 7
  1574. a453 3
  1575.     rcsCheckOut("aliases");
  1576.     if (copy(MAIL_ALIASES, MAIL_ALIASES_TMP, 0666)) {
  1577.     return;
  1578. d457 1
  1579. a457 1
  1580.     if (sed(MAIL_ALIASES_TMP, expr, 0666)) {
  1581. d459 2
  1582. a462 33
  1583.     unlink(MAIL_ALIASES_BAK);
  1584.     rename(MAIL_ALIASES, MAIL_ALIASES_BAK);
  1585.     rename(MAIL_ALIASES_TMP, MAIL_ALIASES);
  1586.     rcsCheckIn("aliases");
  1587.     printf("Added %s to %s mailing list.\n", name, list);
  1588.     edit_mailaliases_file = DONE;
  1589.     return;
  1590. }
  1591.  
  1592. /*
  1593.  *----------------------------------------------------------------------
  1594.  *
  1595.  * rcsCheckOut --
  1596.  *
  1597.  *    Check out a file.
  1598.  *
  1599.  * Results:
  1600.  *    None.
  1601.  *
  1602.  * Side effects:
  1603.  *    Checks out the file.
  1604.  *
  1605.  *----------------------------------------------------------------------
  1606.  */
  1607. static int
  1608. rcsCheckOut(file)
  1609.     char *file;
  1610. {
  1611.     int child;
  1612.     union wait ws;
  1613.     int w;
  1614.  
  1615.     switch (child = fork()) {
  1616. d464 4
  1617. a467 10
  1618.     case -1:
  1619.     fprintf(stderr, "Fork failed: %s\n", strerror(errno));
  1620.     cleanup();
  1621.     /* NOTREACHED */
  1622.  
  1623.     case 0:
  1624.     execlp("co", "co", "-l", file, NULL);
  1625.     fprintf(stderr, "Cannot exec co: %s\n", strerror(errno));
  1626.     exit(EXIT_FAILURE);
  1627.     /* NOTREACHED */
  1628. d469 12
  1629. a480 5
  1630.     default:
  1631.     while ((w = wait(&ws)) > 0 && w != child) {
  1632.         continue;
  1633.     }
  1634.     return ws.w_retcode;
  1635. d482 2
  1636. a483 1
  1637. }
  1638. d485 5
  1639. a489 43
  1640. /*
  1641.  *----------------------------------------------------------------------
  1642.  *
  1643.  * rcsCheckIn --
  1644.  *
  1645.  *    Check in a file.
  1646.  *
  1647.  * Results:
  1648.  *    None.
  1649.  *
  1650.  * Side effects:
  1651.  *    Checks in the file.
  1652.  *
  1653.  *----------------------------------------------------------------------
  1654.  */
  1655. static int
  1656. rcsCheckIn(file)
  1657.     char *file;
  1658. {
  1659.     int child;
  1660.     union wait ws;
  1661.     int w;
  1662.  
  1663.     switch (child = fork()) {
  1664.  
  1665.     case -1:
  1666.     fprintf(stderr, "Fork failed: %s\n", strerror(errno));
  1667.     cleanup();
  1668.     /* NOTREACHED */
  1669.  
  1670.     case 0:
  1671.     dup2(open("/dev/null", O_RDONLY), 0);
  1672.     execlp("ci", "ci", "-u", file, NULL);
  1673.     fprintf(stderr, "Cannot exec ci: %s\n", strerror(errno));
  1674.     exit(EXIT_FAILURE);
  1675.     /* NOTREACHED */
  1676.  
  1677.     default:
  1678.     while ((w = wait(&ws)) > 0 && w != child) {
  1679.         continue;
  1680.     }
  1681.     return ws.w_retcode;
  1682.     }
  1683. d492 1
  1684. d511 2
  1685. a512 2
  1686.     const char *filename;
  1687.     const char *expr;
  1688. d536 1
  1689. a536 1
  1690.     cleanup();
  1691. d588 4
  1692. a591 4
  1693.     const char *dir;
  1694.     const char *username;
  1695.     const char *forward;
  1696.     const char *project;
  1697. a596 1
  1698.     int in, out;
  1699. d611 1
  1700. a611 1
  1701.         cleanup();
  1702. d615 1
  1703. d619 1
  1704. a619 1
  1705.     cleanup();
  1706. d621 1
  1707. d626 1
  1708. a626 1
  1709.     cleanup();
  1710. d629 3
  1711. d633 1
  1712. d635 1
  1713. a635 1
  1714.     cleanup();
  1715. d643 1
  1716. a643 1
  1717.         cleanup();
  1718. d653 1
  1719. d658 1
  1720. d686 1
  1721. d690 1
  1722. a690 1
  1723.  * Routine --
  1724. d692 1
  1725. a692 1
  1726.  *    Inserts a passwd entry into /etc/passwd.
  1727. d705 1
  1728. a705 1
  1729.     const struct passwd *newpwd;
  1730. a706 1
  1731.     char *buf;
  1732. d712 3
  1733. a714 3
  1734.     if ((fd = open(_PATH_PTMP, O_RDWR|O_CREAT|O_EXCL, 0660)) < 0) {
  1735.     fprintf(stderr, "Cannot open %s: %s\n", _PATH_PTMP, strerror(errno));
  1736.     cleanup();
  1737. d717 1
  1738. d723 1
  1739. d734 1
  1740. a734 1
  1741.         unlink(_PATH_PTMP);
  1742. d736 1
  1743. a736 1
  1744.         printf("%s left unchanged\n", _PATH_MASTERPASSWD);
  1745. d739 1
  1746. a739 1
  1747.         cleanup();
  1748. d790 1
  1749. d893 1
  1750. a893 1
  1751.         cleanup();
  1752. d900 1
  1753. a900 1
  1754.  
  1755. d918 1
  1756. a918 1
  1757.     const struct passwd *pwd;
  1758. d987 1
  1759. a987 1
  1760.     printf("Enter 2 for /user2    (spriters)\n");
  1761. d1004 1
  1762. a1004 1
  1763.         strcpy(dir, "/user2");
  1764. d1126 1
  1765. a1126 1
  1766.     cleanup();
  1767. d1133 2
  1768. a1134 2
  1769.     const char *from;
  1770.     const char *to;
  1771. d1166 2
  1772. a1167 1
  1773. cleanup()
  1774. d1171 1
  1775. a1171 1
  1776.     if (rename(_PATH_MASTERPASSWD, _PATH_PTMP)) {
  1777. d1173 2
  1778. a1174 2
  1779.         _PATH_MASTERPASSWD, _PATH_PTMP, strerror(errno));
  1780.     } else if (rename(MASTER_BAK, _PATH_MASTERPASSWD)) {
  1781. d1176 2
  1782. a1177 2
  1783.         MASTER_BAK, _PATH_MASTERPASSWD, strerror(errno));
  1784.     } else if (rename(PASSWD_BAK, _PATH_PASSWD)) {
  1785. d1179 1
  1786. a1179 1
  1787.         PASSWD_BAK, _PATH_PASSWD, strerror(errno));
  1788. d1181 1
  1789. a1181 1
  1790.         unlink(_PATH_PTMP);
  1791. d1184 3
  1792. a1186 2
  1793.     if (unlink(_PATH_PTMP)) {
  1794.         fprintf(stderr, "Cannot unlink %s: %s\n", _PATH_PTMP, strerror(errno));
  1795. d1190 1
  1796. a1190 1
  1797.     if (unlink(MAIL_ALIASES_TMP)) {
  1798. d1192 1
  1799. a1192 1
  1800.         MAIL_ALIASES_TMP, strerror(errno));
  1801. a1209 13
  1802. makedb(file)
  1803.         char *file;
  1804. {
  1805.         int status, pid, w;
  1806.  
  1807.         if (!(pid = vfork())) {
  1808.                 execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
  1809.                 printf("done execl\n");
  1810.                 _exit(127);
  1811.         }
  1812.         while ((w = wait(&status)) != pid && w != -1);
  1813.         return(w == -1 || status);
  1814. }
  1815. @
  1816.  
  1817.  
  1818. 1.6
  1819. log
  1820. @The master uid database is moved from cad to thalm.
  1821. @
  1822. text
  1823. @d20 1
  1824. a20 1
  1825. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.5 90/12/19 16:31:06 rab Exp Locker: kupfer $";
  1826. d1064 1
  1827. a1064 1
  1828.     printf("Enter 5 for /mic      (mic group)\n");
  1829. d1090 1
  1830. a1090 1
  1831.         strcpy(dir, "/mic");
  1832. @
  1833.  
  1834.  
  1835. 1.5
  1836. log
  1837. @Aliases file is under RCS control.  Use ANSI exit #defines.
  1838. (Mike checking in for Bob.)
  1839. @
  1840. text
  1841. @d20 1
  1842. a20 1
  1843. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.4 90/08/13 21:03:03 rab Exp Locker: rab $";
  1844. d55 3
  1845. d932 1
  1846. a932 1
  1847.     printf("Fetching passwd entry from database on cad.\n");
  1848. d944 3
  1849. a946 2
  1850.     execlp("rsh", "rsh", "allspice", "-l", "root", "rsh", "cad", "-l",
  1851.         "account", "=bin/mkpwent", USER_DIR, lastname, group, NULL);
  1852. d965 1
  1853. a965 1
  1854.         fprintf(stderr, "Could't fetch entry from cad\n");
  1855. @
  1856.  
  1857.  
  1858. 1.4
  1859. log
  1860. @Changed mint to allspice.
  1861. @
  1862. text
  1863. @d20 1
  1864. a20 1
  1865. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.3 90/08/13 21:01:17 shirriff Exp Locker: rab $";
  1866. d90 2
  1867. d109 2
  1868. d165 1
  1869. a165 1
  1870.     exit(1);
  1871. d171 1
  1872. a171 1
  1873.     exit(1);
  1874. d187 1
  1875. a187 1
  1876.     case 'q':  case 'Q':    exit(1);
  1877. a255 4
  1878.     unlink(MAIL_ALIASES_BAK);
  1879.     rename(MAIL_ALIASES, MAIL_ALIASES_BAK);
  1880.     rename(MAIL_ALIASES_TMP, MAIL_ALIASES);
  1881.     printf("Done creating account for %s\n", username);
  1882. d261 2
  1883. a262 1
  1884.     exit(0);
  1885. d462 5
  1886. d476 5
  1887. d488 89
  1888. d624 1
  1889. a624 1
  1890.     exit(1);
  1891. d936 1
  1892. a936 1
  1893.     exit(1);
  1894. d944 1
  1895. a944 1
  1896.     exit(1);
  1897. d950 1
  1898. a950 1
  1899.         exit(1);
  1900. d1275 1
  1901. a1275 1
  1902.     exit(1);
  1903. @
  1904.  
  1905.  
  1906. 1.3
  1907. log
  1908. @Added support for shadow passwords.
  1909. @
  1910. text
  1911. @d20 1
  1912. a20 1
  1913. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.2 90/06/28 15:15:20 rab Exp Locker: shirriff $";
  1914. d841 1
  1915. a841 1
  1916.     execlp("rsh", "rsh", "mint", "-l", "root", "rsh", "cad", "-l",
  1917. @
  1918.  
  1919.  
  1920. 1.2
  1921. log
  1922. @Automatically create .forward in home directory.
  1923. @
  1924. text
  1925. @d20 1
  1926. a20 1
  1927. static char rcsid[] = "$Header: /sprite/src/admin/adduser/RCS/adduser.c,v 1.1 90/03/21 11:05:27 rab Exp Locker: rab $";
  1928. a47 1
  1929. #define PASSWD              "/etc/passwd"
  1930. d49 1
  1931. a49 1
  1932. #define PTMP                "/etc/ptmp"
  1933. d156 2
  1934. d191 1
  1935. d216 31
  1936. a246 12
  1937.     unlink(PASSWD_BAK);
  1938.     if (rename(PASSWD, PASSWD_BAK)) {
  1939.         fprintf(stderr, "Cannot rename %s to %s: %s\n",
  1940.         PASSWD, PASSWD_BAK, strerror(errno));
  1941.         cleanup();
  1942.     }
  1943.     if (rename(PTMP, PASSWD)) {
  1944.         fprintf(stderr, "Cannot rename %s to %s: %s\n",
  1945.         PASSWD, PASSWD_BAK, strerror(errno));
  1946.         rename(PASSWD_BAK, PASSWD);
  1947.         cleanup();
  1948.     }
  1949. d465 1
  1950. a465 1
  1951.     sprintf(expr, "/^%s:/s/,$/, %s,/", list, name);
  1952. d684 1
  1953. d686 2
  1954. a687 2
  1955.     if ((fd = open(PTMP, O_RDWR|O_CREAT|O_EXCL, 0444)) < 0) {
  1956.     fprintf(stderr, "Cannot open %s: %s\n", PTMP, strerror(errno));
  1957. d691 6
  1958. d706 1
  1959. a706 1
  1960.         unlink(PTMP);
  1961. d708 1
  1962. a708 1
  1963.         printf("%s left unchanged\n", PASSWD);
  1964. d714 11
  1965. a724 1
  1966.     fprintf(ptmp, "%s:%s:%d:%d:%s:%s:%s\n",
  1967. d729 3
  1968. d737 11
  1969. a747 1
  1970.     fprintf(ptmp, "%s:%s:%d:%d:%s:%s:%s\n",
  1971. d752 3
  1972. a1042 2
  1973.     ps->pw_quota = 0;
  1974.     ps->pw_comment = "";
  1975. d1044 3
  1976. d1140 4
  1977. a1143 1
  1978.     if (rename(PASSWD, PTMP)) {
  1979. d1145 2
  1980. a1146 2
  1981.         PASSWD, PTMP, strerror(errno));
  1982.     } else if (rename(PASSWD_BAK, PASSWD)) {
  1983. d1148 1
  1984. a1148 1
  1985.         PASSWD_BAK, PASSWD, strerror(errno));
  1986. d1150 1
  1987. a1150 1
  1988.         unlink(PTMP);
  1989. d1153 2
  1990. a1154 2
  1991.     if (unlink(PTMP)) {
  1992.         fprintf(stderr, "Cannot unlink %s: %s\n", PTMP, strerror(errno));
  1993. d1178 13
  1994. @
  1995.  
  1996.  
  1997. 1.1
  1998. log
  1999. @Initial revision
  2000. @
  2001. text
  2002. @d20 1
  2003. a20 1
  2004. static char rcsid[] = "$Header$";
  2005. d75 2
  2006. a76 2
  2007. static void createHomeDirectory(const char *dir,
  2008.     const char *username, const char *project, int uid, int gid);
  2009. d123 1
  2010. d193 9
  2011. d228 1
  2012. a228 1
  2013.     createHomeDirectory(real_homedir, username, project,
  2014. d322 1
  2015. d547 1
  2016. a547 1
  2017. createHomeDirectory(dir, username, project, uid, gid)
  2018. d550 1
  2019. d552 2
  2020. d561 1
  2021. d608 4
  2022. d620 14
  2023. @
  2024.